﻿Function Start-WindowsService
{ 
    [cmdletbinding(SupportsShouldProcess=$True,DefaultParameterSetName="Standard")]
    Param( 
        [Parameter(ParameterSetName="Standard",Mandatory=$true,ValueFromPipeline=$true)] 
        [Parameter(ParameterSetName="ExpectedStartupTypeKnown",Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Name,

        [Parameter(ParameterSetName="ExpectedStartupTypeKnown",Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $ExpectedStartupType

         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Start-WindowsService $Name"
    }
    End
    {
        write-verbose "End Start-WindowsService $Name"
        $watch.Stop();
        Write-Verbose "Start-WindowsService duration : $($watch.Elapsed)"
    }
    Process
    {

        $service = Get-WindowsServiceProperties -Name $Name -ErrorAction SilentlyContinue
        if ($service -eq $null)
        {
            Write-Warning "Service $Name doesn't exists"
            return
        }


        switch ($PSCmdlet.ParameterSetName)
        {
           'Standard'
           {
                write-verbose "Start-WindowsService mode Standard"
                if ($service.StartMode -eq 'Disabled')
                {
                     write-Warning "Service $Name is Disabled, so it can't be started"   
                     return    
                }

                if ($service.State -eq 'Running')
                {
                    Write-Warning "Service $Name is already started"
                }
                else
                {
                    Start-Service -Name $Name | out-null
                }
           }
           'ExpectedStartupTypeKnown'
           {
                write-verbose "Start-WindowsService mode ExpectedStartupTypeKnown"
                if ($service.StartMode -eq 'Disabled')
                {
                    if ($ExpectedStartupType.ToLower() -eq 'disabled')
                    {
                        write-verbose "Service $Name is Disabled and its expected startup type is disabled, so it won't be started"
                    }
                    else
                    {
                        write-Warning "Service $Name is Disabled, so it can't be started"   
                    }
                    return
                }

                if ($ExpectedStartupType.ToLower() -eq 'disabled')
                {
                    if ($service.State -eq 'Running')
                    {
                        Write-Warning "Service $Name should be disabled but it is started"
                    }
                    else
                    {
                        Write-Warning "Service $Name should be disabled. It is stopped so it won't be started"                        
                    }   
                }
                else
                {
                    if ($service.State -eq 'Running')
                    {
                        Write-Warning "Service $Name is already started"
                    }
                    else
                    {
                        Start-Service -Name $Name | out-null
                    }
                }
           }
        }       
    }
}

Function Stop-WindowsService
{ 
 [cmdletbinding(SupportsShouldProcess=$True,DefaultParameterSetName="Standard")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="Standard")] 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="ExpectedStartupTypeKnown")] 
        [String] 
        $Name,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="ExpectedStartupTypeKnown")] 
        [String] 
        $ExpectedStartupType,
                
        [Parameter()]
        [Switch]
        $Force
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Stop-WindowsService $Name"
    }
    End
    {
        write-verbose "End Stop-WindowsService $Name"
        $watch.Stop();
        Write-Verbose "Stop-WindowsService duration : $($watch.Elapsed)"
    }
    Process
    {

        $service = Get-WindowsServiceProperties -Name $Name -ErrorAction SilentlyContinue
        if ($service -eq $null)
        {
            Write-Warning "Service $Name doesn't exists"
            return
        }

        switch ($PSCmdlet.ParameterSetName)
        {
           'Standard'
           {        
                write-verbose "Stop-WindowsService mode Standard"
                if ($service.StartMode -eq 'Disabled')
                {
                   write-Warning "Service $Name is Disabled"                      
                   return
                }

                if ($service.State -ne 'Running')
                {
                    Write-Warning "Service $Name is already stopped"
                }
                else
                {
                        
                    Stop-Service -Name $Name -Force:$Force | out-null
                }

           }
           'ExpectedStartupTypeKnown'
           {
                write-verbose "Stop-WindowsService mode ExpectedStartupTypeKnown"
                if ($service.StartMode -eq 'Disabled')
                {
                    if ($ExpectedStartupType.ToLower() -eq 'disabled')
                    {
                        write-verbose "Service $Name is Disabled and its expected startup type is disabled"  
                    }
                    else
                    {
                       write-Warning "Service $Name is Disabled"
                    }
                    return
                }

                if ($ExpectedStartupType.ToLower() -eq 'disabled')
                {
                    if ($service.State -eq 'Running')
                    {
                        Write-Warning "Service $Name should be disabled but it is started, the service will be stopped"
                        Stop-Service -Name $Name -Force:$Force | out-null
                    }
                    else
                    {
                        Write-Warning "Service $Name should be disabled. It is already stopped"                        
                    }   
                }
                else
                {
                    if ($service.State -eq 'Running')
                    {
                        Write-verbose "Service $Name is started, the service will be stopped"
                        Stop-Service -Name $Name -Force:$Force | out-null
                    }
                    else
                    {
                        Write-Warning "Service $Name is already stopped"
                    }
                }
           }
        }
    }       

}


Function Set-ConfigWindowsService
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Name,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $StartMode
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Set-ConfigWindowsService starting mode $StartMode to $Name"
    }
    End
    {
        write-verbose "End Set-ConfigWindowsService starting mode $StartMode to $Name"
        $watch.Stop();
        Write-Verbose "Set-ConfigWindowsService duration : $($watch.Elapsed)"
    }
    Process
    {

    }
}


Function Install-WindowsService
{ 
    [cmdletbinding(SupportsShouldProcess=$True,DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$false,Position=1)] 
        [String] 
        $Name,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false,Position=2)] 
        [String] 
        $Path,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)] 
        [String] 
        $Arguments,


        [Parameter(Mandatory=$true,ParameterSetName='SetCredential')] 
        [String] 
        $UserName,

        [Parameter(Mandatory=$true,ParameterSetName='SetCredential')] 
        [String] 
        $Password
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Install-WindowsService $Name from $Path"
        if ($UserName)
        {
            Write-Verbose "Set credential $UserName to service $Name"
        }

    }
    End
    {
        write-verbose "End Install-WindowsService $Name from $Path"
        $watch.Stop();
        Write-Verbose "Install-WindowsService duration : $($watch.Elapsed)"
    }
    Process
    {
        $service = Get-WindowsServiceProperties -Name $Name -ErrorAction SilentlyContinue
        if ($service -ne $null)
        {
            Write-Warning "Service $Name already exists"
            return
        }

        $file = Get-Item -Path $Path
        if (-not $file)
        {
            throw New-Object System.Exception "Missing service file $Path"
        }

        $servicePath = $file.FullName

        if (![String]::IsNullOrWhiteSpace($Arguments))
        {
            $servicePath += " " + $Arguments
        }

        $commandToExecute = '& "C:\Windows\System32\sc.exe" create $Name binPath= "$servicePath"'

        #Add whatif support
		if($PSBoundParameters['Whatif'])
		{
		    Write-Verbose "Create fake command  to have an echo for this command which doesn't support Whatif : '$($Action.SupportWhatif)'"
            $commandToExecute = "write-output 'WHATIF for unsupported whatif command : " + $commandToExecute + "'" 
		}

		Write-verbose "Command to execute : $commandToExecute"
		Invoke-Command -ScriptBlock ([scriptblock]::create($commandToExecute))

    }
}

Function UnInstall-WindowsService
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] 
        [String] 
        $Name         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin UnInstall-WindowsService $Name from $Path"
    }
    End
    {
        write-verbose "End UnInstall-WindowsService $Name from $Path"
        $watch.Stop();
        Write-Verbose "UnInstall-WindowsService duration : $($watch.Elapsed)"
    }
    Process
    {
        $service = Get-WindowsServiceProperties -Name $Name -ErrorAction SilentlyContinue
        if ($service -eq $null)
        {
            Write-Warning "Service $Name doesn't exists"
            return
        }

        $commandToExecute = '& "C:\Windows\System32\sc.exe" delete $Name'

        #Add whatif support
		if($PSBoundParameters['Whatif'])
		{
		    Write-Verbose "Create fake command  to have an echo for this command which doesn't support Whatif : '$($Action.SupportWhatif)'"
            $commandToExecute = "write-output 'WHATIF for unsupported whatif command : " + $commandToExecute + "'" 
		}

		Write-verbose "Command to execute : $commandToExecute"
		Invoke-Command -ScriptBlock ([scriptblock]::create($commandToExecute))

    }
}

Function Get-WindowsServiceProperties
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Name  
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Get_WindowsServiceProperties $Name"
    }
    End
    {
        write-verbose "End Get-WindowsServiceProperties $Name"
        $watch.Stop();
        Write-Verbose "Get-WindowsServiceProperties duration : $($watch.Elapsed)"
    }
    Process
    {
        
        $service = New-Object System.Object
        $service | Add-Member -type NoteProperty -name Name -value $Name
        $service | Add-Member -type NoteProperty -name DeploymentState -value "Not found"

        #Get the service
        $searchService = Get-WmiObject -Class win32_Service -Filter "Name = '$Name'"
        if ($searchService -ne $null)
        {
            $service.DeploymentState ="Found"
            $searchService | Get-Member -MemberType Property | ForEach-Object{
                $service | Add-Member -MemberType NoteProperty -Name $_.Name  -Value $searchService.$($_.Name) -Force -ErrorAction SilentlyContinue
            }
        }
        else
        {
            return $null
        }

        <#
        if($service.PathName)
        {
            $service.PathName = $service.PathName.replace('"','')

            $fileInfo = Get-ItemProperty $service.PathName
            $service | Add-Member -type NoteProperty -name FileVersionInfo -value $fileInfo.VersionInfo.FileVersion
            $service | Add-Member -type NoteProperty -name ProductName -value $fileInfo.VersionInfo.ProductName
            $service | Add-Member -type NoteProperty -name CompanyName -value $fileInfo.VersionInfo.CompanyName
            $service | Add-Member -type NoteProperty -name CreationTime -value $fileInfo.CreationTime
        }
        #>

        Write-Output $service

    }
}

